package com.baijiayun.live.ui.speakpanel

import android.content.Context
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.Observer
import com.baijiayun.live.ui.R
import com.baijiayun.live.ui.activity.LiveRoomBaseActivity
import com.baijiayun.live.ui.activity.LiveRoomRouterListener
import com.baijiayun.live.ui.base.BasePadFragment
import com.baijiayun.live.ui.base.getViewModel
import com.baijiayun.live.ui.pptpanel.MyPadPPTView
import com.baijiayun.live.ui.removeSwitchableFromParent
import com.baijiayun.live.ui.speakerlist.ItemPositionHelper
import com.baijiayun.live.ui.speakerlist.ItemPositionHelper.ItemAction
import com.baijiayun.live.ui.speakerlist.item.*
import com.baijiayun.livecore.context.LPConstants
import com.baijiayun.livecore.models.LPAwardUserInfo
import com.baijiayun.livecore.models.imodels.IMediaModel
import com.baijiayun.livecore.models.imodels.IUserModel
import com.baijiayun.livecore.utils.CommonUtils
import com.baijiayun.livecore.utils.LPLogger
import com.baijiayun.livecore.viewmodels.impl.LPSpeakQueueViewModel
import com.baijiayun.livecore.wrapper.LPRecorder

/**
 * Created by Shubo on 2019-10-10.
 */
open class SpeakFragment : BasePadFragment() {
    private val TAG: String = "SpeakFragment"

    private lateinit var routerListener: LiveRoomRouterListener
    private val speakViewModel by lazy {
        getViewModel { SpeakViewModel(routerViewModel) }
    }
    private val positionHelper by lazy {
        ItemPositionHelper()
    }
    private val liveRoom by lazy {
        routerViewModel.liveRoom
    }
    private val kickOutObserver by lazy {
        Observer<Unit> {
            it?.let {
                val speakItems = positionHelper.speakItems
                for (speakItem in speakItems) {
                    if (speakItem is LifecycleObserver) {
                        lifecycle.removeObserver(speakItem)
                    }
                }
            }
        }
    }

    private val screenShareEndBackstageObserver by lazy {
        Observer<Unit>{
            it?.let {
                val speakItem = positionHelper.getSpeakItemByIdentity(liveRoom.currentUser.userId)
                if (speakItem is LocalVideoItem) {
                    speakItem.resetOnStopState()
                }
            }
        }
    }

    private val navigateToMainObserver by lazy {
        Observer<Boolean> {
            if (it == true) {
                initSuccess()
                speakViewModel.subscribe()
            }
        }
    }

    private val remotePlayableObserver by lazy {
        Observer<IMediaModel> {
            notifyRemotePlayableChange(it)
        }
    }

    private val presenterChangeObserver by lazy {
        Observer<Pair<String, IMediaModel>> {
            notifyPresenterChange(it)
        }
    }

    private val classEndObserver by lazy {
        Observer<Unit> {
            showClassEnd()
        }
    }
    protected lateinit var container: ViewGroup
    private val speakParams by lazy {
        val height = resources.getDimensionPixelSize(R.dimen.speak_video_height)
        var ratio = 4f / 3
        if (liveRoom.partnerConfig.getDefaultDefinition(true).typeValue >= LPConstants.LPResolutionType._720.typeValue) {
            ratio = 16f / 9
        }
        val width = (ratio * height).toInt()
        LinearLayout.LayoutParams(width, height)
    }

    private val pptViewObserver by lazy {
        Observer<MyPadPPTView> {
            it?.let {
                if (activity is LiveRoomBaseActivity) {
                    positionHelper.setRouterListener((activity as LiveRoomBaseActivity).routerListener)
                }
            }
        }
    }

    private val switch2SpeakObserver by lazy {
        Observer<Switchable> {
            it?.let {
                context?.run {
                    removeSwitchableFromParent(it)
                    val index = positionHelper.getItemSwitchBackPosition(it)
                    if (it is LocalItem) {
                        if (it.hasVideo()) {
                            addSwitchable(it, index)
                        }
                    } else if (it is RemoteItem) {
                        if (it.hasAudio() || it.hasVideo() || it.isKeepAlive) {
                            addSwitchable(it, index)
                        }
                    } else {
                        addSwitchable(it, index)
                    }
                }
            }
        }
    }

    override fun init(view: View) {
        container = view.findViewById(R.id.fragment_speakers_container)
        routerViewModel.speakListCount.value = 0
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is LiveRoomBaseActivity) {
            routerListener = context.routerListener
        }
    }

    override fun getLayoutId(): Int = R.layout.fragment_pad_speakers

    override fun observeActions() {
        super.observeActions()
        routerViewModel.actionNavigateToMain.observeForever(navigateToMainObserver)
        routerViewModel.pptViewData.observeForever(pptViewObserver)
    }

    private fun initSuccess() {
        routerViewModel.actionRequestActiveUsers.observe(this, Observer {
            it?.let { routerViewModel.liveRoom.speakQueueVM.requestActiveUsers() }
        })

        routerViewModel.notifyRemotePlayableChanged.observeForever(remotePlayableObserver)
        /**
         * 切换主讲人,完成主讲区域和发言列表切换
         * 只需要考虑speakList切到mainVideo,mainVideo做相应处理
         */
        routerViewModel.notifyPresenterChange.observeForever(presenterChangeObserver)

        routerViewModel.actionAttachLocalVideo.observe(this, Observer {
            it?.let {
                if (it) {
                    attachLocalVideo()
                } else {
                    detachLocalVideo()
                }
            }
        })

        routerViewModel.actionAttachLocalAVideo.observe(this, Observer {
            it?.let {
                if (it) {
                    attachLocalAVideo()
                }
            }
        })
        routerViewModel.notifyLocalPlayableChanged.observe(this, Observer {
            it?.run {
                notifyLocalPlayableChange(it.first, it.second)
            }
        })

        routerViewModel.notifyLocalVideoChanged.observe(this, Observer {
            it?.run {
                notifyLocalPlayableChange(it)
            }
        })

        routerViewModel.actionAttachLocalAudio.observe(this, Observer {
            it?.run {
                attachLocalAudio()
            }
        })

        routerViewModel.switch2SpeakList.observeForever(switch2SpeakObserver)

        routerViewModel.switch2MaxScreen.observe(this, Observer {
            it?.let {
                if (it.switchableType != SwitchableType.SpeakItem) {
                    routerViewModel.speakListCount.value = container.childCount
                }
            }
        })

        routerViewModel.notifyCloseRemoteVideo.observe(this, Observer {
            it?.let {
                closeRemoteVideo(it)
            }
        })

        routerViewModel.notifyAward.observe(this, Observer {
            it?.let { awardModel ->
                if (awardModel.isFromCache && awardModel.value.recordAward != null) {
                    awardModel.value.recordAward.forEach { entry ->
                        val playable: Playable? = positionHelper.getPlayableItemByUserNumber(entry.key)
                        playable?.notifyAwardChange(entry.value.count)
                    }
                    return@Observer
                }
                if (awardModel.value.to == "-1") {
                    return@Observer
                }
                val playable = positionHelper.getPlayableItemByUserNumber(awardModel.value.to)
                val userInfo: LPAwardUserInfo? = awardModel.value.recordAward?.get(awardModel.value.to)
                if (playable == null) {
                    // 台下点赞
                    val user = getUser(awardModel.value.to)
                    // 大班老师，找不到user，说明user在小班不响应点赞
                    if (user == null && routerViewModel.liveRoom.isTeacherOrAssistant) {
                        return@Observer
                    }
                    // 不是一个组且只看本组
                    if (user?.group != routerViewModel.liveRoom.currentUser.group && routerViewModel.liveRoom.onlineUserVM.enableMyGroupUsersPublish()) {
                        return@Observer
                    }
                    routerViewModel.action2Award.value = CommonUtils.getEncodePhoneNumber(user?.name
                            ?: (userInfo?.name?:"")) to awardModel
                } else {
                    // 不是一个组且只看本组
                    if (playable.user?.group != routerViewModel.liveRoom.currentUser.group && routerViewModel.liveRoom.onlineUserVM.enableMyGroupUsersPublish()) {
                        return@Observer
                    }
                    playable.notifyAwardChange(userInfo?.count ?: 0)
                    routerViewModel.action2Award.value = CommonUtils.getEncodePhoneNumber(playable.user.name) to awardModel
                }
            }
        })
        // 合流课程刷新主讲人名称
        routerViewModel.notifyMixModePresenterChange.observe(this, Observer {
            it?.let {
                if (!routerViewModel.liveRoom.speakQueueVM.isMixModeOn) {
                    return@Observer
                }
                val item = positionHelper.getSpeakItemByIdentity(LPSpeakQueueViewModel.FAKE_MIX_STREAM_USER_ID)
                if (item is RemoteVideoItem && it.name != null) {
                    item.refreshUserName(it.name, it.type)
                }
            }
        })

        routerViewModel.classEnd.observeForever(classEndObserver)

        routerViewModel.kickOut.observeForever(kickOutObserver)

        routerViewModel.screenShareEndBackstage.observeForever(screenShareEndBackstageObserver)
    }

    open fun getUser(userNumber: String): IUserModel? {
        if (liveRoom.currentUser.number == userNumber){
            return liveRoom.currentUser
        }
        return liveRoom.onlineUserVM.getUserByNumber(userNumber)
    }

    open fun showClassEnd() {
        positionHelper.removeAllItem()
        container.removeAllViews()
        routerViewModel.speakListCount.value = 0
    }

    private fun notifyPresenterChange(pair: Pair<String, IMediaModel>?) {
        pair?.let {
            var actionList: List<ItemAction>? = null
            val userId = it.first
            if (TextUtils.isEmpty(userId)) {
                // 主讲人退出关闭合流
                actionList = positionHelper.processPresenterChangeItemActions(null)
                val pptView = routerViewModel.pptViewData.value
                if (pptView is MyPadPPTView && pptView.closeByExtCamera && routerViewModel.extCameraData.value?.second != null
                        && !routerViewModel.extCameraData.value?.first.isNullOrEmpty()) {
                    // 关闭主讲人分享的辅助摄像头或者屏幕分享userid_1
                    closeExtMedia()
                }
            } else {
                var speakItem = positionHelper.getSpeakItemByIdentity(userId)
                if (speakItem == null && routerListener.liveRoom.currentUser.userId != userId) {
                    speakItem = createRemotePlayableItem(it.second)
                    actionList = positionHelper.processPresenterChangeItemActions(speakItem)
                } else if (speakItem == null && routerListener.liveRoom.currentUser.userId == userId) {
                    val localItem = createLocalPlayableItem()
                    localItem?.run {
                        actionList = positionHelper.processUnActiveLocalPresenterItemActions(this)
                        refreshPlayable()
                    }
                } else {
                    actionList = positionHelper.processPresenterChangeItemActions(speakItem)
                }
            }
            actionList?.run {
                takeItemActions(this, true)
                for (action in this) {
                    if (action.action == ItemPositionHelper.ActionType.ADD && action.speakItem is LocalItem) {
                        (action.speakItem as LocalItem).invalidVideo()
                    }
                }
            }
        }
    }

    private fun notifyRemotePlayableChange(mediaModel: IMediaModel?) {
        mediaModel?.let {
            // 处理老师的辅助摄像头或者辅助屏幕分享，按配置项决定在PPT区域还是发言列表显示
            if (routerViewModel.liveRoom.templateType == LPConstants.TemplateType.DOUBLE_CAMERA
                    && !routerViewModel.liveRoom.partnerConfig.enableShowPPTWithAssistCameraOn
                    && it.user.type == LPConstants.LPUserType.Teacher) {
                if (it.mediaSourceType == LPConstants.MediaSourceType.ExtCamera
                        || it.mediaSourceType == LPConstants.MediaSourceType.ExtScreenShare
                        || it.mediaSourceType == LPConstants.MediaSourceType.ExtMedia) {
                    handleExtMedia(it)
                    return
                }
            }
            val identity = if (it.mediaSourceType == LPConstants.MediaSourceType.ExtCamera
                    || it.mediaSourceType == LPConstants.MediaSourceType.ExtScreenShare
                    || it.mediaSourceType == LPConstants.MediaSourceType.ExtMedia) {
                it.user.userId + "_1"
            } else {
                it.user.userId
            }
            var item = positionHelper.getSpeakItemByIdentity(identity)
            LPLogger.d(TAG, "remotePlayable ${it.user.name}--${it.mediaId}--${it.isVideoOn}--${it.isAudioOn}")
            if (item == null) {
                item = createRemotePlayableItem(it)
            }
            val remoteItem = item as RemoteVideoItem?
            remoteItem?.run {
                setMediaModel(it)
                val isSpeakClosed = !hasAudio() && !hasVideo()
                if (!isVideoClosedByUser || isSpeakClosed) {
                    takeItemActions(positionHelper.processItemActions(this), true)
                }
                refreshPlayable()
            }
        }
    }

    private fun notifyLocalPlayableChange(isVideoOn: Boolean, isAudioOn: Boolean? = null) {
        var item = positionHelper.getSpeakItemByIdentity(routerViewModel.liveRoom.currentUser.userId)
        var itemActions: List<ItemAction>?
        val audioOn = isAudioOn ?: liveRoom.getRecorder<LPRecorder>().isAudioAttached
        if (item == null) {
            if (isVideoOn || audioOn) {
                item = createLocalPlayableItem()
            }
        }
        item?.run {
            if (this is LocalVideoItem) {
                setShouldStreamVideo(isVideoOn)
                itemActions = positionHelper.processItemActions(this)
                takeItemActions(itemActions)
                if (isAudioOn == null) refreshPlayable() else refreshPlayable(isVideoOn, isAudioOn)
            }
        }
    }

    /**
     * 处理辅助摄像头的流
     * 三分屏辅助摄像头默认在白板或者全屏并且替换掉ppt(切换逻辑和ppt一致)
     * 辅助摄像头关闭后ppt还原到白板区
     */
    private fun handleExtMedia(iMediaModel: IMediaModel) {
        val pptView = routerViewModel.pptViewData.value as MyPadPPTView
        val remoteItem: Switchable?
        if (iMediaModel.user.userId == routerViewModel.extCameraData.value?.first) {
            remoteItem = routerViewModel.extCameraData.value?.second
        } else {
            val switchable = routerViewModel.extCameraData.value?.second
            if (switchable != null) {
                removeSwitchableFromParent(switchable)
            }
            remoteItem = createRemotePlayableItem(iMediaModel) as RemoteVideoItem
            routerViewModel.extCameraData.value = iMediaModel.user.userId to remoteItem
        }
        remoteItem as RemoteVideoItem
        if (iMediaModel.isVideoOn) {
            if (!pptView.closeByExtCamera) {
                remoteItem.setVideoCloseByUser(false)
                remoteItem.syncPPTExtCamera(pptView)
                pptView.closePPTbyExtCamera()
            }
        } else {
            if (!pptView.closeByExtCamera) {
                pptView.closePPTbyExtCamera()
            }
            pptView.closeByExtCamera = false
            pptView.syncPPTExtCamera(remoteItem)
            removeSwitchableFromParent(remoteItem)
        }
        remoteItem.setMediaModel(iMediaModel)
        remoteItem.refreshPlayable()
    }

    private fun closeExtMedia() {
        val item = routerViewModel.extCameraData.value?.second
        item?.let {
            val pptView = routerViewModel.pptViewData.value as MyPadPPTView
            if (!pptView.closeByExtCamera) {
                pptView.closePPTbyExtCamera()
            }
            pptView.closeByExtCamera = false
            pptView.syncPPTExtCamera(it)
            removeSwitchableFromParent(it)
            if (it is RemoteItem) {
                it.stopStreaming()
            }
        }
    }

    private fun addSwitchable(switchable: Switchable, index: Int = -1, checkPresenter: Boolean = false) {
        // 把view切到main区域
        if (switchable.switchableType == SwitchableType.MainItem) {
            if (routerViewModel.mainVideoItem?.isPlaceholderItem == true) {
                (routerViewModel.mainVideoItem as PlaceholderItem).onRemove()
            }
            // notifyRemote和presenterchange都可能会引起主讲人切换，因为switchable.switchableType判断的是core层真实的主讲人交换没有
            if (checkPresenter && routerViewModel.liveRoom.speakQueueVM.isCloseOldPresenterMedia) {
                if (TextUtils.equals(routerViewModel.mainVideoItem?.identity, routerViewModel.liveRoom.currentUser.userId)){
                    detachLocalAVideo()
                }
            }
            switchable.replaceVideoSync(routerViewModel.mainVideoItem)
        } else {
            val child = switchable.view
            addView(child, index, switchable)
        }
        routerViewModel.speakListCount.value = container.childCount
    }

    open fun addView(child: View, index: Int = -1, switchable: Switchable) {
        if (index == -1) {
            container.addView(child, speakParams)
        } else {
            var value = index
            val pptView = routerViewModel.pptViewData.value
            if (pptView is MyPadPPTView) {
                if (pptView.pptStatus == SwitchableStatus.MainVideo || pptView.closeByExtCamera) {
                    value -= 1
                }
            }
            if (container.childCount < value) {
                value = container.childCount
            }
            container.addView(child, value, speakParams)
        }
    }

    /**
     * 判断是移除发言列表view还是主讲区view或者ppt区域
     */
    private fun removeSwitchable(switchable: Switchable) {
        val index = container.indexOfChild(switchable.view)
        if (index == -1) {
            removeSwitchableFromParent(switchable)
            routerViewModel.removeMainVideo.value = switchable
        } else {
            container.removeView(switchable.view)
        }
        routerViewModel.speakListCount.value = container.childCount
    }

    private fun closeRemoteVideo(remoteItem: RemoteItem) {
        val actionList = positionHelper.processUserCloseAction(remoteItem)
        takeItemActions(actionList)
    }

    private fun createLocalPlayableItem(): LocalVideoItem? {
        return if (::routerListener.isInitialized) {
            val localItem = LocalVideoItem(container, routerListener)
            localItem.notifyAwardChange(getAwardCount(liveRoom.currentUser.number))
            localItem.isForceKeepAlive = forceKeepAlive()
            lifecycle.addObserver(localItem)
            localItem
        } else {
            null
        }
    }

    open fun forceKeepAlive() = false

    private fun createRemotePlayableItem(iMediaModel: IMediaModel): RemoteItem? {
        return if (::routerListener.isInitialized) {
            val remoteItem = RemoteVideoItem(container, iMediaModel, routerListener)
            remoteItem.notifyAwardChange(getAwardCount(iMediaModel.user.number))
            lifecycle.addObserver(remoteItem)
            remoteItem
        } else {
            null
        }
    }

    private fun takeItemActions(actions: List<ItemAction>?, checkPresenter: Boolean = false) {
        actions?.run {
            for (action in actions) {
                when (action.action) {
                    ItemPositionHelper.ActionType.ADD -> {
                        val switchable = action.speakItem as Switchable
                        removeSwitchableFromParent(switchable)
                        val value = action.value
                        addSwitchable(switchable, value, checkPresenter)
                    }
                    ItemPositionHelper.ActionType.REMOVE -> {
                        if (action.speakItem is LocalVideoItem) {
                            (action.speakItem as LocalVideoItem).onRemove()
                        } else if (action.speakItem is RemoteVideoItem) {
                            (action.speakItem as RemoteVideoItem).onRemove()
                        }
                        if (action.speakItem is LifecycleObserver) {
                            lifecycle.removeObserver(action.speakItem as LifecycleObserver)
                        }
                        removeSwitchable(action.speakItem as Switchable)
                    }
                    ItemPositionHelper.ActionType.FULLSCREEN -> (action.speakItem as Switchable).switchToMaxScreen()
                }
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        routerViewModel.kickOut.removeObserver(kickOutObserver)
        routerViewModel.actionNavigateToMain.removeObserver(navigateToMainObserver)
        routerViewModel.notifyRemotePlayableChanged.removeObserver(remotePlayableObserver)
        routerViewModel.notifyPresenterChange.removeObserver(presenterChangeObserver)
        routerViewModel.classEnd.removeObserver(classEndObserver)
        routerViewModel.pptViewData.removeObserver(pptViewObserver)
        routerViewModel.switch2SpeakList.removeObserver(switch2SpeakObserver)
        routerViewModel.screenShareEndBackstage.removeObserver(screenShareEndBackstageObserver)
        (view as ViewGroup).removeAllViews()
    }

    companion object {
        fun newInstance() = SpeakFragment()
    }

    private fun getAwardCount(number: String?): Int {
        return routerViewModel.awardRecord[number]?.count ?: 0
    }
}